package com.egoo.ticket.server.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.egoo.ticket.server.config.mq.MqCommonUtil;
import com.egoo.ticket.server.config.mq.RabbitMqConfig;
import com.egoo.ticket.server.dao.*;
import com.egoo.ticket.server.pojo.dto.SystemMsgDto;
import com.egoo.ticket.server.pojo.dto.TaskTimeOutRecordDto;
import com.egoo.ticket.server.pojo.entity.*;
import com.egoo.ticket.server.pojo.enums.FieldEnum;
import com.egoo.ticket.server.pojo.vo.TaskTimeOutRecordVo;
import com.egoo.ticket.server.pojo.vo.WorkOrderTypeNodeVo;
import com.egoo.ticket.server.project.ProjectConstant;
import com.egoo.ticket.server.project.jincheng.JinchengTimeOutJudge;
import com.egoo.ticket.server.service.EripDataSynService;
import com.egoo.ticket.server.service.ScheduService;
import com.egoo.ticket.server.service.WorkOrderLogService;
import com.egoo.ticket.server.utils.common.ConstantCode;
import com.egoo.ticket.server.utils.common.DbResponse;
import com.egoo.ticket.server.utils.common.ResponseConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author：victor_tang
 * @Date ：2020/4/10
 * @Description：调度任务实现类
 */
@Service
@Slf4j
//@Transactional(rollbackFor = Exception.class)
public class ScheduServiceImpl implements ScheduService {
	@Autowired
	private RabbitMqConfig rabbitMqConfig;
	@Autowired
	private AmqpTemplate amqpTemplate;
	@Autowired
	private TaskTimeOutRecordDao taskTimeOutRecordDao;
	@Autowired
	private WorkOrderDao workOrderDao;
	@Autowired
	private EwsUserDao ewsUserDao;
	@Autowired
	private WorkOrderTypeNodeDao workOrderTypeNodeDao;
	@Autowired
	private WorkOrderLogService workOrderLogService;
	@Autowired
	private EripDataSynService eripDataSynService;
	@Autowired
	private WorkOrderRelationMapper workOrderRelationMapper;
	@Autowired
	private JinchengTimeOutJudge jinchengTimeOutJudge;
	@Autowired
	private MqCommonUtil mqCommonUtil;

	@Value("${server.H5-workorder-detail-url}")
	private String h5WorkorderDetailUrl;
	@Value("${server.project-sign}")
	private String projectSign;

	public static SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
	public static SimpleDateFormat sdfTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	@Override
	public void workOrderTimeOut() {

		// 获取未超时或者未发送超时提醒的任务记录信息
		TaskTimeOutRecordDto taskTimeOutRecordDto =
				new TaskTimeOutRecordDto();
		taskTimeOutRecordDto.setIsTimeOut(ConstantCode.N);
		taskTimeOutRecordDto.setIsSendMsg(ConstantCode.N);
		List<TaskTimeOutRecordVo> dataList =
				taskTimeOutRecordDao.selectListByCondition(taskTimeOutRecordDto);
		if (dataList == null) {
			return;
		}
		// 处理工单节点超时
		for (TaskTimeOutRecordVo taskTimeOutRecordVo : dataList) {
			handleTimeOut(taskTimeOutRecordVo);
		}
	}

	/**
	 * TODO 删除已超时，已发送超时提醒短信得超时记录
	 *
	 * @param
	 * @author: victor_tang
	 * @createtime: 2020/4/13 18:51
	 * @return: void
	 */
	private void deleteTaskTimeOutRecord() {
		TaskTimeOutRecord taskTimeOutRecord = new TaskTimeOutRecord();
		taskTimeOutRecord.setIsTimeOut(ConstantCode.Y);
		taskTimeOutRecord.setIsSendMsg(ConstantCode.Y);
		taskTimeOutRecordDao.deleteByCondition(taskTimeOutRecord);
	}

	/**
	 * TODO 获取工单流程节点超时时间，判断该任务是否超时
	 *
	 * @param taskTimeOutRecordVo 1
	 * @author: victor_tang
	 * @createtime: 2020/2/21 14:54
	 * @return: void
	 */
	private void handleTimeOut(TaskTimeOutRecordVo taskTimeOutRecordVo) {

		String nodeIdString = taskTimeOutRecordVo.getNodeId();
		if (StringUtils.isEmpty(nodeIdString)) {
			return;
		}
		String processInstanceId = taskTimeOutRecordVo.getProcessInstanceId();
		if (StringUtils.isEmpty(processInstanceId)) {
			return;
		}
		// 根据流程实例id，获取工单当前状态信息
		WorkOrder workOrder = workOrderDao.selectByProcessInstanceId(processInstanceId);
		if (workOrder == null || ConstantCode.WorkOrderState.ALREDAY_CLOSE == workOrder.getStatusId()
				|| ConstantCode.WorkOrderState.ALREAAY_CASE == workOrder.getStatusId()
		) {
			// 已关闭和已完成工单，直接跳过
//			taskTimeOutRecordDao.deleteByPrimaryKey(taskTimeOutRecordVo.getTaskId());
			return;
		}

		// 处理工单超时业务
		handleTimeOut(taskTimeOutRecordVo, workOrder);

	}


	/**
	 * TODO 发送待处理工单短信提醒
	 *
	 * @param taskTimeOutRecordVo 1
	 * @param workOrder           2
	 * @author: victor_tang
	 * @createtime: 2020/3/27 17:07
	 * @return: void
	 */
	private void sendMsgWarn(TaskTimeOutRecordVo taskTimeOutRecordVo, WorkOrder workOrder) {
		if (ConstantCode.Y.equals(taskTimeOutRecordVo.getIsSendMsg())) {
			// 已经发送过30分钟超时短信提醒，直接跳过
			return;
		}
		long intervalTimes =
				System.currentTimeMillis() - taskTimeOutRecordVo.getStartTime().getTime();

		long times =
				intervalTimes - ConstantCode.TaskTimeOutRecordConstant.TIME_LENGTH * 60 * 1000;
		if (times < 0) {
			// 未到达约定发提醒短信时间
			return;
		}
//		// 给当前处理人发送提醒短信
//		boolean isExistSendSuccess = sendMsgToCurrentHandler(workOrder);
//
//		if (isExistSendSuccess) {
//			// 存在短信提醒成功的员工后，修改工单超时记录为是否发送短信为Y
//			updateTaskRecordIsSendMsg(taskTimeOutRecordVo);
//		}
		// 存在短信提醒成功的员工后，修改工单超时记录为是否发送短信为Y
		updateTaskRecordIsSendMsg(taskTimeOutRecordVo);
	}

	/**
	 * TODO 更新提醒短信发送状态为已发送
	 *
	 * @param taskTimeOutRecordVo 1
	 * @author: victor_tang
	 * @createtime: 2020/3/27 18:04
	 * @return: void
	 */
	private void updateTaskRecordIsSendMsg(TaskTimeOutRecordVo taskTimeOutRecordVo) {
		TaskTimeOutRecord taskTimeOutRecord = new TaskTimeOutRecord();
		taskTimeOutRecord.setTaskId(taskTimeOutRecordVo.getTaskId());
		taskTimeOutRecord.setIsSendMsg(ConstantCode.Y);
		taskTimeOutRecordDao.updateByPrimaryKeySelective(taskTimeOutRecord);
	}

	/**
	 * TODO 发送提醒短信给当前工单处理人
	 *
	 * @param workOrder 1
	 * @author: victor_tang
	 * @createtime: 2020/3/27 17:38
	 * @return: void
	 */
	private boolean sendMsgToCurrentHandler(WorkOrder workOrder) {
		boolean isSendSuccess = false;
		List<EwsUser> ewsUsers = getCurrentHandlerInfo(workOrder);
		if (ewsUsers == null || ewsUsers.size() == 0) {
			return isSendSuccess;
		}
		for (EwsUser ewsUser : ewsUsers) {
			boolean flag = sendWarnMsg(workOrder, ewsUser);
			if (flag) {
				isSendSuccess = true;
			}
		}
		return isSendSuccess;
	}

	/**
	 * TODO 获取当前处理信息列表
	 *
	 * @param workOrder 1
	 * @author: victor_tang
	 * @createtime: 2020/3/27 18:26
	 * @return: java.utils.List<com.egoo.ews.service.vo.EwsUser>
	 */
	private List<EwsUser> getCurrentHandlerInfo(WorkOrder workOrder) {
		String currentHandlerIds = workOrder.getCurrentHandlerId();
		if (StringUtils.isEmpty(currentHandlerIds)) {
			return null;
		}
		List<String> userIds = Arrays.asList(currentHandlerIds.split(","));
		Map<String, Object> searchMap = new HashMap<>(4);
		searchMap.put("tenantId", workOrder.getTenantId());
		searchMap.put("userIds", userIds);
		return ewsUserDao.selectAllUserList(searchMap);
	}

	/**
	 * TODO 发送提醒短信
	 *
	 * @param workOrder 1
	 * @param ewsUser   2
	 * @author: victor_tang
	 * @createtime: 2020/4/1 12:33
	 * @return: boolean
	 */
	private boolean sendWarnMsg(WorkOrder workOrder, EwsUser ewsUser) {
		String userPhone = ewsUser.getPhone();
		if (StringUtils.isEmpty(userPhone)) {
			log.info(ewsUser.getId() + "员工电话为空，无法发送工单30分钟未处理提醒短信！");
			return false;
		}
		String content =
				getMsgTemplateContent(ConstantCode.TemplateConfig.WARN_MSG_TEMPLATE_NAME);
		if (StringUtils.isEmpty(content)) {
			log.info("{工单未处理提醒}短信模板为空，不知道该发什么短信！");
			return false;
		}
		content = content.replace("{workOrderId}", workOrder.getId())
				.replace("{workOrderUrl}", h5WorkorderDetailUrl);

		JSONObject jsonObject = new JSONObject();
		jsonObject.put("phoneNumber", userPhone);
		jsonObject.put("content", content);
		jsonObject.put("msgTypeName", ConstantCode.TemplateConfig.WARN_MSG_TEMPLATE_NAME);
		jsonObject = handleMsgSendLogField(jsonObject, workOrder);
		log.info("发送30分钟工单未处理提醒短信参数为：{}" + jsonObject);
		DbResponse dbResponse = eripDataSynService.sendMsg(jsonObject);
		if (ResponseConstant.RES_SUCCESS_CODE == dbResponse.getRetCode()) {
			return true;
		}
		return false;

	}

	/**
	 * TODO 添加短信发送日志记录必须字段
	 *
	 * @param jsonObject 1
	 * @param workOrder  2
	 * @author: victor_tang
	 * @createtime: 2020/4/15 14:27
	 * @return: com.alibaba.fastjson.JSONObject
	 */
	private JSONObject handleMsgSendLogField(JSONObject jsonObject,
											 WorkOrder workOrder) {
		jsonObject.put("workOrderId", workOrder.getId());
		jsonObject.put("userId", ConstantCode.SYSTEM_OPERATION_LOGO);
		jsonObject.put("tenantId", workOrder.getTenantId());
		return jsonObject;
	}

	/**
	 * TODO 处理工单超时业务
	 * 正泰超时规则（一期以工单类型节点配置的处理时长限制作为超时规则，二期待定）
	 *
	 * @param taskTimeOutRecordVo 1
	 * @param workOrder           2
	 * @author: victor_tang
	 * @createtime: 2020/2/21 14:53
	 * @return: void
	 */
	private void handleTimeOut(TaskTimeOutRecordVo taskTimeOutRecordVo, WorkOrder workOrder) {
		if (ConstantCode.Y.equals(taskTimeOutRecordVo.getIsTimeOut())) {
			// 已超时的任务记录直接跳出
			return;
		}
		Boolean flagBoolean = timeOutHandleForProject(taskTimeOutRecordVo, workOrder);
		if (!flagBoolean) {
			return;
		}
//		// 发送超时提醒短信和系统消息给当前工单处理人
//		sendTimeOutMsgToCurrentHandler(workOrder);

		// 待处理超时，任务超时状态为已超时
		updateTimeOutState(taskTimeOutRecordVo.getTaskId(), ConstantCode.Y);

		// 修改工单超时状态
		updateWorkOrderTimeOut(workOrder.getId(), taskTimeOutRecordVo.getProcessInstanceId(), FieldEnum.IS_TIME_OUT.getCode());

		// 工单日志添加一条，待回访超时记录
		addWorkOrderLog(taskTimeOutRecordVo, workOrder);
		log.info("工单超时后触发器发布的key为："+workOrder.getId());
		JSONObject jsonObject = new JSONObject();
		jsonObject.put(ConstantCode.MsgParam.WORK_ORDER_ID,workOrder.getId());
		jsonObject.put(ConstantCode.MsgParam.MSG_TARGET_SIGN,ConstantCode.SysDictCode.SEND_MSG_CURRENT_HANDLER);
		jsonObject.put(ConstantCode.MsgParam.MSG_TYPE,ConstantCode.WorkOrderLogType.LOG_TYPE_TIME_OUT);
		String mqContent = jsonObject.toJSONString();
		amqpTemplate.convertAndSend(rabbitMqConfig.WORKORDER_SHORTMSG,mqContent);
		mqCommonUtil.pushToMsgGeneralQueue(ConstantCode.MsgNotifyType.TIME_OUT_NOTIFY,workOrder.getId());
	}

	/**
	 * @Author: Donny_dong
	 * @Description: 不同的超时规则处理
	 * @Param:
	 * @return:
	 * @Date: 2020/8/19
	 */
	private boolean timeOutHandleForProject(TaskTimeOutRecordVo taskTimeOutRecordVo, WorkOrder workOrder) {
		boolean flagBoolean = false;
		if (ProjectConstant.ProjectSign.PRODUCT.equals(projectSign)
				|| null == projectSign
				|| ProjectConstant.ProjectSign.SUNONG.equals(projectSign)
				|| ProjectConstant.ProjectSign.SANXIANG.equals(projectSign)
				|| ProjectConstant.ProjectSign.ZHENENG.equals(projectSign)) {
			// 30分钟未处理，发送短信提醒
			sendMsgWarn(taskTimeOutRecordVo, workOrder);
			// 判断工单是否超时
			flagBoolean = isTimeOut(taskTimeOutRecordVo);
		} else if (ProjectConstant.ProjectSign.JINCHNEG.equals(projectSign)) {
			flagBoolean = jinchengTimeOutJudge.handleTimeOutForJinCheng(taskTimeOutRecordVo, workOrder);
		}
		return flagBoolean;
	}

	/**
	 * TODO 发送超时提醒短信给当前工单处理人
	 *
	 * @param workOrder 1
	 * @author: victor_tang
	 * @createtime: 2020/3/27 17:38
	 * @return: void
	 */
	private void sendTimeOutMsgToCurrentHandler(WorkOrder workOrder) {
		List<EwsUser> ewsUsers = getCurrentHandlerInfo(workOrder);
		if (ewsUsers == null || ewsUsers.size() == 0) {
			log.info("发送超时短信时，工单当前处理人信息为空;");
			return;
		}
		List<String> ids = new ArrayList<>();
		for (EwsUser ewsUser : ewsUsers) {
			// 发送超时提醒短信
			sendTimeOutMsg(workOrder, ewsUser);
			ids.add(ewsUser.getId());
		}
		// 推送超时提醒给消息中心
		pushTimeOutMsgToMsgCenter(workOrder, ids);

	}

	/**
	 * TODO 推送超时提醒给消息中心
	 *
	 * @param workOrder 1
	 * @param ids       2
	 * @author: victor_tang
	 * @createtime: 2020/3/31 18:33
	 * @return: void
	 */
	private void pushTimeOutMsgToMsgCenter(WorkOrder workOrder, List<String> ids) {
		// 获取超时提醒消息模板
		String content = getMsgTemplateContent(ConstantCode.TemplateConfig.TIME_OUT_MSG_TEMPLATE_NAME);
//		String content = "您有协办工单{workOrderId}+{workOrderUrl}已超时，请及时处理！";
		if (StringUtils.isEmpty(content)) {
			log.info("推送消息中心的模板为空，无法推送消息！");
			return;
		}
		content = content.replace("{workOrderId}", workOrder.getId())
				.replace("{workOrderUrl}", "");
		SystemMsgDto systemMsgDto = new SystemMsgDto();
		systemMsgDto.setTitle(ConstantCode.TemplateConfig.TIME_OUT_MSG_TEMPLATE_NAME);
		systemMsgDto.setContent(content);
		systemMsgDto.setTargets(ids);
		systemMsgDto.setSenderId(ConstantCode.SystemMsgConfig.SENDER_ID_SYS);
		JSONObject jsonObject = getPushMsgParamRemark(workOrder.getId(),
				ConstantCode.SystemMsgConfig.IS_JUMP_Y,
				ConstantCode.SystemMsgConfig.WORK_ORDER);
		systemMsgDto.setRemark(jsonObject);
		eripDataSynService.sendSystemMsg(systemMsgDto);
	}

	/**
	 * TODO 设置推送消息字段remark值
	 *
	 * @param orderId    1
	 * @param isJump     2
	 * @param systemType 3
	 * @author: victor_tang
	 * @createtime: 2020/4/1 16:00
	 * @return: com.alibaba.fastjson.JSONObject
	 */
	private JSONObject getPushMsgParamRemark(String orderId, String isJump,
											 String systemType) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put(ConstantCode.SystemMsgConfig.REMARK_ORDER_ID, orderId);
		jsonObject.put(ConstantCode.SystemMsgConfig.REMARK_IS_JUMP, isJump);
		jsonObject.put(ConstantCode.SystemMsgConfig.REMARK_SYSTEM_TYPE, systemType);
		return jsonObject;
	}

	/**
	 * TODO 发送工单超时短信
	 *
	 * @param workOrder 1
	 * @param ewsUser   2
	 * @author: victor_tang
	 * @createtime: 2020/4/1 12:34
	 * @return: void
	 */
	private void sendTimeOutMsg(WorkOrder workOrder, EwsUser ewsUser) {
		String userPhone = ewsUser.getPhone();
		if (StringUtils.isEmpty(userPhone)) {
			log.info(ewsUser.getId() + "员工电话为空，无法给当前处理人发送工单超时短信！");
			return;
		}
		String content = getMsgTemplateContent(ConstantCode.TemplateConfig.TIME_OUT_MSG_TEMPLATE_NAME);
		if (StringUtils.isEmpty(content)) {
			log.info("{工单超时提醒}模板为空，不知道该发什么短信！");
			return;
		}
		content = content.replace("{workOrderId}", workOrder.getId())
				.replace("{workOrderUrl}", h5WorkorderDetailUrl);
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("phoneNumber", userPhone);
		jsonObject.put("content", content);
		jsonObject.put("msgTypeName", ConstantCode.TemplateConfig.TIME_OUT_MSG_TEMPLATE_NAME);
		jsonObject = handleMsgSendLogField(jsonObject, workOrder);
		log.info("发送超时工单超时未处理短信参数为：{}" + jsonObject);
		DbResponse dbResponse = eripDataSynService.sendMsg(jsonObject);
		if (ResponseConstant.RES_FAIL_CODE == dbResponse.getRetCode()) {
			log.error("超时短信发送失败！");
			return;
		}
	}

	/**
	 * TODO 修改任务超时记录
	 *
	 * @param taskId
	 * @param isTimeOut
	 * @return
	 */
	private int updateTimeOutState(String taskId, String isTimeOut) {
		TaskTimeOutRecord taskTimeOutRecord = new TaskTimeOutRecord();
		taskTimeOutRecord.setTaskId(taskId);
		taskTimeOutRecord.setIsTimeOut(isTimeOut);
		return taskTimeOutRecordDao.updateByPrimaryKeySelective(taskTimeOutRecord);
	}

	/**
	 * TODO 修改工单超时状态
	 *
	 * @param processInstanceId
	 * @param isTimeOut
	 */
	private void updateWorkOrderTimeOut(String workOrderId, String processInstanceId, String isTimeOut) {
		WorkOrderRelation workOrderRelation = getByWorkOrderId(workOrderId);
		workOrderRelation.setIsTimeOut(isTimeOut);
		Integer integer = workOrderRelationMapper.updateWorkOrderRelation(workOrderRelation);
	}

	/**
	 * @Author: Donny_dong
	 * @Description: 根据工单id获取一条WorkOrderRelation
	 * @Param:
	 * @return:
	 * @Date: 2020/4/26
	 */
	private WorkOrderRelation getByWorkOrderId(String workOrderId) {
		WorkOrderRelation workOrderRelation = new WorkOrderRelation();
		workOrderRelation.setWorkOrderId(workOrderId);
		workOrderRelation = workOrderRelationMapper.selectWorkOrderRelation(workOrderRelation);
		return workOrderRelation;
	}

	/**
	 * TODO 添加日志记录
	 *
	 * @param taskTimeOutRecordVo
	 * @param workOrder
	 */
	private void addWorkOrderLog(TaskTimeOutRecordVo taskTimeOutRecordVo, WorkOrder workOrder) {
		// 工单日志添加一条超时记录
		WorkOrderLog workOrderLog = new WorkOrderLog();
		workOrderLog.setWorkOrderId(workOrder.getId());
		workOrderLog.setWorkOrderNodeId(Long.valueOf(taskTimeOutRecordVo.getNodeId()));
		workOrderLog.setWorkOrderStatusId(workOrder.getStatusId());
		workOrderLog.setLogType(ConstantCode.WorkOrderLogType.LOG_TYPE_TIMEOUT);
		workOrderLogService.addSave(workOrderLog);
	}

	/**
	 * TODO 判断工单是否超时
	 *
	 * @param taskTimeOutRecordVo 1
	 * @author: victor_tang
	 * @createtime: 2020/2/21 14:28
	 * @return: java.lang.Boolean
	 */
	private Boolean isTimeOut(TaskTimeOutRecordVo taskTimeOutRecordVo) {
		WorkOrderTypeNodeVo workOrderTypeNodeVo =
				workOrderTypeNodeDao.getNodeByWorkOrderNodeId(Long.valueOf(taskTimeOutRecordVo.getNodeId()));
		if (workOrderTypeNodeVo == null) {
			log.info(taskTimeOutRecordVo.getNodeId() + "类型节点信息未找到！");
			return false;
		}
		// 节点处理时长（小时）
		Double dealtime = workOrderTypeNodeVo.getContent().getDouble("dealtime");
		if (dealtime == null) {
			// 未设置处理时长永远不超时
			return false;
		}
		if (dealtime <= 0) {
			// 小于等于0立即超时
			return true;
		}
		if (taskTimeOutRecordVo.getStartTime() == null) {
			log.info(taskTimeOutRecordVo.getTaskId() + "任务超时处理开始时间丢失");
			return false;
		}
		dealtime = dealtime * 60 * 60 * 1000;
		long timeOutPoint = taskTimeOutRecordVo.getStartTime().getTime() + dealtime.longValue();
		// 超时时间点小于等于当前时间，该工单超时
		if (timeOutPoint <= System.currentTimeMillis()) {
			return true;
		}
		return false;
	}

	/**
	 * TODO 获取短信模板内容
	 *
	 * @param filterName 1
	 * @author: victor_tang
	 * @createtime: 2020/3/31 17:47
	 * @return: java.lang.String
	 */
	private String getMsgTemplateContent(String filterName) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("name", filterName);
		JSONArray templateArr =
				eripDataSynService.getTemplateByFilterCondition(jsonObject);
		if (templateArr == null || templateArr.size() == 0) {
			return null;
		}
		return templateArr.getJSONObject(0).getString("remark");
	}

	/**
	 * TODO 删除已处理超时记录
	 *
	 * @author: victor_tang
	 * @createtime: 2020/9/8 11:04
	 * @return: void
	 */
	@Override
	public void deleteAlreadyHanleTimeOutRecord() {
		// 删除已超时，已发送超时提醒短信得超时记录
		deleteTaskTimeOutRecord();
	}
}
